package com.lsh.payment.worker.task;

import com.dangdang.ddframe.job.api.JobExecutionMultipleShardingContext;
import com.lsh.base.trace.id.filter.TraceIdSetter;
import com.lsh.payment.api.model.basevo.ExceptionStatus;
import com.lsh.payment.core.exception.BusinessException;
import com.lsh.payment.core.model.payasync.EmailModel;
import com.lsh.payment.core.model.payenum.RefundTaskStatus;
import com.lsh.payment.core.model.payenum.RefundTaskType;
import com.lsh.payment.core.model.refund.RefundTask;
import com.lsh.payment.core.service.async.PayEventBus;
import com.lsh.payment.core.service.refund.IRefundTaskService;
import com.lsh.payment.core.util.DateUtil;
import com.lsh.payment.worker.service.RefundTaskJopService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * Project Name: lsh-payment
 *
 * @author peter
 * @date 18/6/4
 * 北京链商电子商务有限公司
 * Package
 * desc:
 */
@Slf4j
public abstract class AbstractPayElasticJob extends AbstractDataFlowElasticJob<RefundTask> {

    @Value("${to.user.email}")
    private String userEmail;

    @Autowired
    private RefundTaskJopService refundTaskJopService;

    @Autowired
    private IRefundTaskService refundTaskService;

    @Override
    public List<RefundTask> fetchData(JobExecutionMultipleShardingContext jobExecutionMultipleShardingContext) {
        TraceIdSetter.set();
        Integer taskType = this.getRefundTaskType().getValue();
        Integer times = this.getDealTimes();
        Integer excludeStatus = this.getExcludeStatus().getValue();
        log.info("[taskType is {}] [max times is {}] [excludeStatus is " + excludeStatus + "]", taskType, times);
        List<RefundTask> refundTaskList = refundTaskJopService.getRefundTasks(taskType, times, excludeStatus);

        if (refundTaskList == null || refundTaskList.isEmpty()) {

            return Collections.emptyList();
        }

        return refundTaskList;
    }

    @Override
    public boolean processData(JobExecutionMultipleShardingContext jobExecutionMultipleShardingContext, RefundTask refundTask) {
        try {

            int times = refundTask.getTimes() + 1;
            boolean process;
            try {
                process = this.processTask(refundTask);
            } catch (Exception e) {
                log.error("退款失败",e);
//                throw new BusinessException(ExceptionStatus.E2001006.getCode(), "退款失败");
                this.sendEmail(userEmail, new BusinessException(ExceptionStatus.E2001006.getCode(), "退款失败"));
                process = false;
            }
            refundTaskService.addRefundDealTimes(refundTask.getId(), times);
            if (process) {
                this.updateRefundTaskStatus(refundTask, RefundTaskStatus.TASK_SUCCESS);
            } else {
                this.updateRefundTaskStatus(refundTask, RefundTaskStatus.TASK_FAIL);

                if (times > 9) {
                    StringBuilder builder = new StringBuilder("【退款任务处理】流水号 (")
                            .append(refundTask.getRefId()).append(")处理(")
                            .append(times).append(")次失败,请人工处理。。");
                    this.sendEmail(userEmail, builder.toString());
                }
            }
        } catch (BusinessException e) {
            //TODO 发送邮件
            this.sendEmail(userEmail, e);
            log.error("业务异常:" + e.getCode() + e.getMessage());
        } catch (Exception e) {
            log.error("服务端异常", e);
        }

        return true;
    }

    private boolean updateRefundTaskStatus(RefundTask refundTask, RefundTaskStatus refundTaskStatus) {

        if (refundTask.getStatus() == refundTaskStatus.getValue()) {
            return true;
        }

        RefundTask refundTask4update = new RefundTask();
        refundTask4update.setRefId(refundTask.getRefId());
        refundTask4update.setUpdatedAt(new Date());
        refundTask4update.setTaskType(refundTask.getTaskType());
        refundTask4update.setStatus(refundTaskStatus.getValue());

        return refundTaskService.updateByRefIdAndType(refundTask4update) > 0;
    }

    /**
     * 查询任务类型
     *
     * @return 返回类型
     */
    protected abstract RefundTaskType getRefundTaskType();

    /**
     * 执行次数
     *
     * @return 返回结果
     */
    protected abstract Integer getDealTimes();

    /**
     * 获得排除状态
     *
     * @return 返回状态信息
     */
    protected abstract RefundTaskStatus getExcludeStatus();

    /**
     * 处理退款请求
     *
     * @param refundTask 退款任务
     */
    protected abstract Boolean processTask(RefundTask refundTask);

    /**
     * 发送异常邮件
     *
     * @param userEmails 邮件
     * @param ex         异常信息
     */
    protected void sendEmail(String userEmails, BusinessException ex) {
        String[] userEmailarray = userEmails.split(",");
        String title = "退款预警_" + DateUtil.defaultDate(new Date());

        PayEventBus.post(new EmailModel(ex.getMessage() + "\n" + DateUtil.defaultTimestamp(new Date()), title, userEmailarray));
    }

    /**
     * 预警邮件
     * @param userEmails  邮件地址
     * @param ex          异常信息
     */
    protected void sendEmail(String userEmails, String ex) {
        String[] userEmailarray = userEmails.split(",");
        String title = "退款预警_" + DateUtil.defaultDate(new Date());

        PayEventBus.post(new EmailModel(ex, title, userEmailarray));
    }

}
